package com.dbflow5.query;

import com.dbflow5.SqlUtils;
import com.dbflow5.StringUtils;
import com.dbflow5.config.FlowManager;
import com.dbflow5.database.DatabaseWrapper;
import com.dbflow5.query.property.IProperty;
import com.dbflow5.sql.Query;

import java.util.ArrayList;
import java.util.List;

/**
 * Description: an INDEX class that enables you to index a specific column from a table. This enables
 * faster retrieval on tables, while increasing the database file size. So enable/disable these as necessary.
 */
public class Index<TModel> implements Query {
    /**
     * @return The name of this index.
     */
    String indexName;
    /**
     * @return The table this INDEX belongs to.
     */
    Class<TModel> table;

    private final List<NameAlias> columns = new ArrayList<>();
    /**
     * @return true if the index is unique
     */
    boolean isUnique = false;

    public Index(String indexName, Class<TModel> table){
        this.indexName = indexName;
        this.table = table;
    }

    @Override
    public String getQuery() {
        StringBuilder builder = new StringBuilder();
        builder.append("CREATE ");
        builder.append(isUnique? "UNIQUE " : "");
        builder.append("INDEX IF NOT EXISTS ");
        StringUtils.appendQuotedIfNeeded(builder, indexName);
        builder.append(" ON ").append(FlowManager.getTableName(table));
        builder.append("(");
        StringUtils.appendList(builder, columns);
        builder.append(")");
        return builder.toString();
    }

    /**
     * If true, will append the UNIQUE statement to this trigger.
     *
     * @param unique true if unique. If created again, a [SQLiteException] is thrown.
     * @return This instance.
     */
    public Index<TModel> unique(boolean unique) {
        isUnique = unique;
        return this;
    }

    /**
     * The table to execute this Index on.
     *
     * @param properties The properties to create an index for.
     * @return This instance.
     */
    public Index<TModel> on(IProperty<?>... properties) {
        for(IProperty<?> property : properties){
            and(property);
        }
        return this;
    }

    /**
     * The table to execute this Index on.
     *
     * @param firstAlias   The table to execute index on.
     * @param columns The columns to create an index for.
     * @return This instance.
     */
    public Index<TModel> on(NameAlias firstAlias, NameAlias... columns) {
        and(firstAlias);
        for(NameAlias nameAlias : columns){
            and(nameAlias);
        }
        return this;
    }

    /**
     * Appends a column to this index list.
     *
     * @param property The name of the column. If already exists, this op will not be added
     * @return This instance.
     */
    public Index<TModel> and(IProperty<?> property) {
        if (!columns.contains(property.nameAlias())) {
            columns.add(property.nameAlias());
        }
        return this;
    }

    /**
     * Appends a column to this index list.
     *
     * @param columnName The name of the column. If already exists, this op will not be added
     * @return This instance.
     */
    public Index<TModel> and(NameAlias columnName) {
        if (!columns.contains(columnName)) {
            columns.add(columnName);
        }
        return this;
    }

    public void createIfNotExists(DatabaseWrapper databaseWrapper) {
        if (columns.isEmpty()) {
            throw new IllegalStateException("There should be at least one column in this index");
        }
        databaseWrapper.execSQL(getQuery());
    }

    public void drop(DatabaseWrapper databaseWrapper) {
        SqlUtils.dropIndex(databaseWrapper, indexName);
    }

    public static <T> Index<T> indexOn(Class<T> clazz, String indexName, IProperty<?>... property) {
        return SQLite.index(indexName, clazz).on(property);
    }

    public static <T> Index<T> indexOn(Class<T> clazz, String indexName, NameAlias firstNameAlias, NameAlias... arrayOfNameAlias) {
        return SQLite.index(indexName, clazz).on(firstNameAlias, arrayOfNameAlias);
    }
}



